<template>
    <div class="app-popup" :data-type="props.type" :style="[popupStyle]">
        <div class="mask" :class="[{ 'active': props.show }]" @click="maskTap"></div>
        <div :class="['popup', props.type, { 'active': props.show }]">
            <div class="cross-center gap header" v-if="props.showTitle || props.showIcon">
                <div class="box-grow-1">
                    <slot name="title" v-if="props.showTitle">
                        <text>{{ props.title }}</text>
                    </slot>
                </div>
                <div class="box-grow-0">
                    <slot name="icon" v-if="props.showIcon">
                        <AppIcon icon="Esc" @click="close"></AppIcon>
                    </slot>
                </div>
            </div>
            <div class="content">
                <slot></slot>
            </div>
            <!-- <AppSafeAreaInsetBottom v-if="['bottom', 'left', 'right'].includes(props.type)"></AppSafeAreaInsetBottom> -->
        </div>
    </div>
</template>

<script setup lang="ts" name="AppPopup">
/**
 * PopUp 弹出层
 * @description 从uniapp移植的组件,类似于抽屉组件,多了一个中间弹出的类型
 * @slot default 默认主体插槽
 * @slot title 标题插槽
 * @slot icon 右上角图标插槽
 * @event {Function} update:show 更新show事件
 * @event {Function} close-leave 关闭弹窗动画结束事件
 * @event {Function} maskClick 遮罩点击事件
 * @event {Function} maskClick 遮罩点击事件
 * @example <AppPopup v-model:show="true"></AppPopup>
 */

export type AppPopupProps = {
    /**是否显示 */
    show?: boolean
    /**弹出层类型 */
    type?: 'top' | 'bottom' | 'center' | 'left' | 'right'
    /**标题 */
    title?: string
    /**是否显示标题 */
    showTitle?: boolean
    /**显示退出图标 */
    showIcon?: boolean
    /**圆角(单位px) */
    radius?: number | string
    /*是否开启动画 */
    animation?: boolean
    /**动画时间 */
    duration?: number
    /**点击遮罩是否关闭 */
    isMaskClose?: boolean
    /**遮罩背景色 */
    maskBg?: string
}

const props = withDefaults(defineProps<AppPopupProps>(), {
    show: false,
    type: 'bottom',
    title: '',
    showTitle: true,
    showIcon: true,
    radius: 8,
    animation: true,
    duration: 300,
    isMaskClose: true,
    maskBg: 'rgba(0, 0, 0, 0.4)',
})

const emit = defineEmits(['update:show', 'closeLeave', 'maskClick'])

/**动画时间 */
const duration = computed(() => {
    if (!props.animation) {
        return 0
    }
    return props.duration
})

const popupStyle = computed(() => {
    return {
        '--duration': props.animation ? `${duration.value / 1000}s` : duration.value,
        '--maskBg': props.maskBg,
        '--radius': `${props.radius}rpx`,
    }
})

/**点击遮罩时触发的事件 */
function maskTap() {
    emit('maskClick')
    if (!props.isMaskClose) return
    close()
}

/**关闭弹出层关闭 */
function close() {
    emit('update:show', false)
}
const { start, stop } = useTimeoutFn(() => {
    emit('closeLeave')
    stop()
}, duration.value, { immediate: false })

watch(() => props.show, (val) => {
    val ? start() : stop()
})

</script>

<style scoped lang="scss">
.app-popup {
    --zIndex: 1000;
    --transitionTimingFunction: ease-in-out;

    .mask {
        position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        background-color: var(--maskBg);
        transition-property: opacity, z-index;
        transition: var(--duration) var(--transitionTimingFunction);
        opacity: 0;
        z-index: -1;

        &.active {
            opacity: 1;
            z-index: var(--zIndex);
        }
    }

    .popup {
        position: fixed;
        z-index: var(--zIndex);
        overflow: hidden;
        background-color: #fff;

        .header {
            height: 96rpx;
            padding: 0 20rpx;
        }
    }

    .top,
    .left,
    .right,
    .bottom {
        transition: transform, var(--duration) var(--transitionTimingFunction);
    }

    .top {
        right: 0;
        top: 0;
        left: 0;
        transform: translateY(-100%);
        border-radius: 0 0 var(--radius) var(--radius);

        &.active {
            transform: translateY(0);
        }
    }

    .bottom {
        right: 0;
        bottom: 0;
        left: 0;
        transform: translateY(100%);
        border-radius: var(--radius) var(--radius) 0 0;

        &.active {
            transform: translateY(0);
        }
    }

    .left {
        top: 0;
        bottom: 0;
        left: 0;
        transform: translateX(-100%);
        border-radius: 0 var(--radius) var(--radius) 0;

        &.active {
            transform: translateX(0);
        }
    }

    .right {
        top: 0;
        bottom: 0;
        right: 0;
        transform: translateX(100%);
        border-radius: var(--radius) 0 0 var(--radius);

        &.active {
            transform: translateX(0);
        }
    }

    .center {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%) scale(0.7);
        transition: var(--duration) var(--transitionTimingFunction);
        transition-property: opacity, transform, z-index;
        border-radius: var(--radius);
        opacity: 0;
        z-index: -1;

        &.active {
            transform: translate(-50%, -50%) scale(1);
            opacity: 1;
            z-index: var(--zIndex);
        }
    }
}
</style>